#ifndef _M_VIRTUALHOST_H_
#define _M_VIRTUALHOST_H_

#include <iostream>
#include <google/protobuf/map.h>
#include <string>
#include <vector>
#include <cassert>
#include <sstream>
#include <functional>
#include <mutex>

#include "../mqcommon/mqProto.pb.h"
#include "../mqcommon/logger.hpp"
#include "../mqcommon/helper.hpp"

#include "binding.hpp"
#include "exchange.hpp"
#include "message.hpp"
#include "msgqueue.hpp"

namespace MyRabbitMQ
{
    //虚拟机类
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;

        VirtualHost(const std::string& name,const std::string& dbfilename, const std::string& baseMessageDir)
        :m_name(name)
        ,m_exchanges(std::make_shared<ExchangeManager>(dbfilename))
        ,m_msgqueues(std::make_shared<MsgQueueManager>(dbfilename))
        ,m_bindings(std::make_shared<BindingManager>(dbfilename))
        ,m_messages(std::make_shared<MessageManager>(baseMessageDir))
        {
            //恢复历史消息::恢复消息数据, 恢复历史消息需要声明队列, 声明队列需要队列名称
            MsgQueueMap queues = m_msgqueues->getMsgQueueAll();
            for(auto& queue : queues)
            {
                assert(m_messages->declareQueueMessageManager(queue.first));
            }
        }

        //声明交换机
        bool declareExchange(const std::string &name, protoMQ::ExchangeType type, 
        bool isDurable, bool isAutoDelete, const google::protobuf::Map<std::string, std::string> &args)
        {
            return m_exchanges->declareExchange(name,type,isDurable, isAutoDelete,args);
        }

        //删除交换机, 删除交换机要顺便删除交换机的相关绑定信息
        bool deleteExchange(const std::string& name)
        {
            bool ret = m_bindings->deleteExchangeBindings(name);
            if(!ret)
            {
                LOG(logLevel::ERROR) << "执行失败:解除交换机相关绑定队列出现问题" << std::endl;
                return false;
            }
            
            ret = m_exchanges->deleteExchange(name);
            
            if(!ret)
            {
                LOG(logLevel::ERROR) << "执行失败:交换机管理句柄删除时出现问题" << std::endl;
                return false;
            }
            
            return true;
        }

        //判断交换机是否存在
        bool existsExchange(const std::string& name)
        {
            return m_exchanges->exists(name);
        }

        //查询交换机
        Exchange::ptr selectExchange(const std::string& name)
        {
            return m_exchanges->getExchange(name);            
        }

        //查询交换机
        ExchangeMap selectExchange()
        {
            return m_exchanges->getExchangeAll();
        }

        //声明队列
        bool declareMsgQueue(const std::string &name,bool isUnique, bool isDurable, 
        bool isAutoDelete, const google::protobuf::Map<std::string, std::string> &args)
        {
            //初始化队列的消息管理句柄
            if(!m_messages->declareQueueMessageManager(name)) 
            {
                LOG(logLevel::ERROR) << "执行失败:队列-消息管理句柄初始化队列出现问题" << std::endl;
                return false;
            }
            return m_msgqueues->declareMsgQueue(name,isUnique,isUnique,isAutoDelete,args);
        }
        
        //删除队列, 要顺便删除队列的相关绑定信息
        bool deleteMsgQueue(const std::string& name)
        {
            bool ret = m_messages->deleteQueueMessageManager(name);
            if(!ret)
            {
                LOG(logLevel::ERROR) << "执行失败:队列-消息管理句柄删除队列出现问题" << std::endl;
                return false;
            }

            ret = m_bindings->deleteMsgQueueBindings(name);
            if(!ret)
            {
                LOG(logLevel::ERROR) << "执行失败:绑定信息管理句柄删除绑定出现问题" << std::endl;
                return false;
            }

            return m_msgqueues->deleteMsgQueue(name);
        } 

        //判断队列是否存在
        bool existsMsgQueue(const std::string& name)
        {
            return m_msgqueues->exists(name);
        }

        //查询队列
        MsgQueue::ptr selectMsgQueue(const std::string& name)
        {
            return m_msgqueues->getMsgQueue(name);
        }

        //查询队列
        MsgQueueMap selectMsgQueue()
        {
            return m_msgqueues->getMsgQueueAll();
        }

        //添加绑定
        bool Bind(const std::string& ename, const std::string& qname, 
        const std::string& bindingKey)
        {
            //绑定的交换机和队列必须存在, 如果不存在则不进行绑定并提示用户
            if(!m_exchanges->exists(ename))
            {
                LOG(logLevel::ERROR) << "执行失败:未存在交换机" << std::endl;
                return false;
            }
            
            if(!m_msgqueues->exists(qname))
            {
                LOG(logLevel::ERROR) << "执行失败:未存在队列" << std::endl;
                return false;
            }

            return m_bindings->declareBinding(ename,qname,bindingKey,
            m_exchanges->getExchange(ename)->m_isDurable && m_msgqueues->getMsgQueue(qname)->m_isUnique);
        }

        //解除绑定
        bool unBind(const std::string& ename,const std::string& qname)
        {
            //绑定的交换机和队列必须存在, 如果不存在则不进行绑定并提示用户
            if(!m_exchanges->exists(ename))
            {
                LOG(logLevel::ERROR) << "执行失败:未存在交换机" << std::endl;
                return false;
            }
            
            if(!m_msgqueues->exists(qname))
            {
                LOG(logLevel::ERROR) << "执行失败:未存在队列" << std::endl;
                return false;
            }

            return m_bindings->deleteBinding(ename,qname);
        }

        //获取指定交换机的所有绑定信息
        msgQueueBindingMap selectBindings(const std::string& ename)
        {
            return m_bindings->getExchangeBindings(ename);           
        }

        //获取指定绑定信息
        Binding::ptr selectBinding(const std::string& ename, const std::string& qname)
        {
            return m_bindings->getBinding(ename,qname);
        }

        //向队列发布消息
        bool basicPublish(const std::string &qname, const protoMQ::BaseProperties *base,
                    const std::string &data)
        {
            //判断队列是否存在
            if(!m_msgqueues->exists(qname))
            {
                LOG(logLevel::ERROR) << "执行失败:未存在队列" << std::endl;
                return false;
            }

            return m_messages->insert(qname,base,data,m_msgqueues->getMsgQueue(qname)->m_isDurable);
        }

        //从队列消费消息
        pbMessagePtr basicConsume(const std::string& qname)
        {
            return m_messages->front(qname);
        }

        //确认消息
        bool basicAck(const std::string& qname,const std::string& id)
        {
            return m_messages->ack(qname, id);
        }
    
        void clear()
        {
            m_exchanges->clear();
            m_msgqueues->clear();
            m_bindings->clear();
            m_messages->clear();
        }

    private:
        //管理句柄
        ExchangeManager::ptr m_exchanges;
        MsgQueueManager::ptr m_msgqueues;
        BindingManager::ptr m_bindings;
        MessageManager::ptr m_messages;

        //虚拟机名称
        std::string m_name;
    };

};
#endif




